﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;

namespace MetroToolbox.Interactivity
{
    public abstract class TriggerAction<T> : TriggerAction where T : DependencyObject
    {
        protected override sealed Type AssociatedObjectTypeConstraint { get { return typeof(T); } }

        protected new T AssociatedObject { get { return base.AssociatedObject as T; } }
    }

    
//    [DefaultTriggerAttribute(typeof(ButtonBase), typeof(EventTrigger), "Click")] 
//    [DefaultTriggerAttribute(typeof(UIElement), typeof(EventTrigger), "MouseLeftButtonDown")] 
    public abstract class TriggerAction : DependencyObject, IAttachedObject
    {
        public readonly static DependencyProperty IsEnabledProperty = DependencyProperty.Register(
            "IsEnabled", 
            typeof(bool), 
            typeof(TriggerBase), 
            new PropertyMetadata(true));

        public bool IsEnabled
        {
            get { return (bool)this.GetValue(IsEnabledProperty); }
            set { this.SetValue(IsEnabledProperty, value); }
        }

        protected DependencyObject AssociatedObject { get; private set; }

        protected virtual Type AssociatedObjectTypeConstraint { get { return typeof(DependencyObject); } }

        public void Attach(DependencyObject dependencyObject)
        {
            if (dependencyObject == null)
            {
                throw new ArgumentNullException("dependencyObject");
            }

            if (!AssociatedObjectTypeConstraint.GetTypeInfo().IsAssignableFrom(dependencyObject.GetType().GetTypeInfo()))
            {
                throw new ArgumentException("Cannot attach to object, does not meet AssociatedObjectTypeConstraint", "dependencyObject");
            }

            AssociatedObject = dependencyObject;
            OnAttached();
        }

        public void Detach()
        {
            OnDetaching();
            AssociatedObject = null;
        }

        protected virtual void OnAttached() { }

        protected virtual void OnDetaching() { }

        protected abstract void Invoke(Object parameter);

        DependencyObject IAttachedObject.AssociatedObject { get { return this.AssociatedObject; } }

        internal void InvokeAction(Object parameter)
        {
            if (IsEnabled)
            {
                Invoke(parameter);
            }
        }
    }
}
